
from PyQt5.QtWidgets import QMainWindow,QVBoxLayout,QLabel,QTreeWidgetItem,QToolButton,QFrame,QSizePolicy,QFileDialog
from PyQt5.QtGui import QIcon,QPixmap,QPainter
from PyQt5 import QtGui
from PyQt5.QtCore import QDateTime,QTimer,Qt
from PyQt5.QtSvg import QSvgRenderer
from ui.uiMain import Ui_MainWindow
from displayWidget import DisplayWidget
from trainNetWidget import TrainNetWidget
from configThreshWidget import ConfigThreshWidget
from configRuleWidget import ConfigRuleWidget
from db import db
from abnormalHandle import AbnormalHandle
from threshHandle import classify,getDescribeByLabel
import json
from util import *

IconDir="./icon/"

def svgToPixmap(svgPath,size):
    svgRender=QSvgRenderer()
    svgRender.load(svgPath)
    pixmap=QPixmap(size[0],size[1])
    pixmap.fill(Qt.transparent)
    painter=QPainter(pixmap)
    svgRender.render(painter)
    return pixmap

def loadText(filePath):
    with open(filePath,'r') as fi:
        text=fi.read()
        fi.close()
        return text

TIMEFORMAT="yyyy-MM-dd hh:mm:ss"
BEGINTIME=QDateTime.fromString('2020-04-08 08:20:00',TIMEFORMAT)

def getDeviceNameByTableName(deviceList,tableName):
    for zsb in deviceList:
        if tableName==zsb["table_name"]:
            return zsb["device_name"]

class MainWidget(QMainWindow,Ui_MainWindow):
    def __init__(self,parent=None):
        super(MainWidget,self).__init__(parent)
        self.setupUi(self)
        self.setComponentProperty()

        self.con = db.connect(True)
        self.deviceList = db.getDeviceList(self.con)

        self.initUi()
        self.setStyleSheet(loadText("ui/main.css"))
        self.connectSignals()
        self.dragging = False
        self.doOnce = False
        self.abnormalHandle = {}

    def __del__(self):
        self.con.close()

    def initUi(self):
        self.setWindowIcon(QIcon(IconDir+"main.svg"))
        self.updateTime()
        self.setInfoNormal()
        self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowSystemMenuHint|Qt.WindowMinMaxButtonsHint)
        self.label_titleIcon.setPixmap(svgToPixmap(IconDir+'main.svg',(60,60)))

        self.widgetDisplayContainer=QFrame(self)
        self.widgetDisplayContainer.setLayout(QVBoxLayout())
        self.widgetDisplayContainer.setContentsMargins(0,0,0,0)
        self.widgetDisplayContainer.layout().setContentsMargins(0,0,0,0)
        self.widgetDisplayContainer.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
        self.widgetDisplay={}
        for zsb in self.deviceList:
            dw=DisplayWidget(self)
            dw.setProperty("tableName",zsb['table_name'])
            dw.setProperty("deviceName", zsb['device_name'])
            dw.hide()
            self.widgetDisplay[zsb['table_name']]=dw
        self.widgetTrainNet=TrainNetWidget(self)
        self.widgetConfigThresh=ConfigThreshWidget(self)
        self.widgetConfigRule=ConfigRuleWidget(self)
        self.tb_display.setProperty("selected", 'true')
        for tableName in self.widgetDisplay:
            self.widgetDisplayContainer.layout().addWidget(self.widgetDisplay[tableName])
        self.mainLayout.addWidget(self.widgetDisplayContainer)
        self.mainLayout.addWidget(self.widgetTrainNet)
        self.mainLayout.addWidget(self.widgetConfigThresh)
        self.mainLayout.addWidget(self.widgetConfigRule)
        self.widgetTrainNet.hide()
        self.widgetConfigThresh.hide()
        self.widgetConfigRule.hide()
        self.tb_min.setIcon(QIcon(IconDir+"min.svg"))
        self.tb_max.setIcon(QIcon(IconDir+"restore.svg"))
        self.tb_close.setIcon(QIcon(IconDir+"close.svg"))
        self.tb_display.setIcon(QIcon(IconDir+"display.svg"))
        self.tb_train.setIcon(QIcon(IconDir+"trainModel.svg"))
        self.tb_configThresh.setIcon(QIcon(IconDir+"configThresh.svg"))
        self.tb_configRule.setIcon(QIcon(IconDir+"configRule.svg"))

        self.tb_logHide.setIcon(QIcon(IconDir+"hideDown.svg"))
        self.label_logBannerIcon.setPixmap(svgToPixmap(IconDir+"logBanner.svg",(25,25)))
        self.tb_logShow=QToolButton(self)
        self.tb_logShow.setToolTip("展开日志面板")
        self.tb_logShow.setToolTipDuration(2000)
        self.tb_logShow.setObjectName('tb_logShow')
        self.tb_logShow.setFixedSize(47,26)
        self.tb_logShow.setIcon(QIcon(IconDir+"showUp.svg"))
        self.updateLogShowBtnLoc()
        self.tb_logShow.hide()

        self.tb_treeHide.setIcon(QIcon(IconDir+"hideLeft.svg"))
        self.tb_treeShow=QToolButton(self)
        self.tb_treeShow.setToolTip("展开管理树")
        self.tb_treeShow.setToolTipDuration(2000)
        self.tb_treeShow.setObjectName("tb_treeShow")
        self.tb_treeShow.setFixedSize(37, 26)
        self.tb_treeShow.setIcon(QIcon(IconDir+"showRight.svg"))
        self.updateTreeShowBtnLoc()
        self.tb_treeShow.hide()

        # self.cb_abnormalHandle.addItem("")

        self.treeWidget.setColumnCount(1)
        root = QTreeWidgetItem()
        root.setText(0,'设备列表')
        self.treeWidget.addTopLevelItem(root)
        root=self.treeWidget.topLevelItem(0)
        root.setExpanded(True)
        #====与数据库相关的ui初始化====
        self.treeItemDict={}
        for item in self.deviceList:
            treeItem=QTreeWidgetItem()
            treeItem.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
            treeItem.setText(0,item['device_name'])
            treeItem.setIcon(0,QIcon(IconDir + "greendot.svg"))
            self.treeWidget.itemClicked.connect(self.onTreeItemClicked)
            root.addChild(treeItem)
            self.treeItemDict[item['table_name']]=root.child(root.childCount()-1)
        root.child(0).setSelected(True)

        #====连接绘图窗口====
        self.curTime=BEGINTIME
        self.cur=self.con.cursor()
        for tableName in self.widgetDisplay:
            self.widgetDisplay[tableName].nextRowCallback=self.nextRowCallback
        self.timer2=QTimer()
        self.timer2.setInterval(1000)
        self.timer2.timeout.connect(self.dbTimeout)
        self.timer2.start()

        self.curWD=self.widgetDisplay[self.deviceList[0]['table_name']]
        self.curWD.show()
        self.cb_abnormalHandle.addItems(["拉依达","格拉布斯","肖维涅","t检验"])
        self.le_loadModel.setText("./default.tf")

    def nextRowCallback(self, tableName):
        self.cur.execute("select * from %s where 采集时间='%s' " % (tableName, self.curTime.toString(TIMEFORMAT)))
        dic = db.getZSBOneRow(self.cur)
        if dic is None:
            self.setTreeItemStatus(tableName,False)
            return None
        else:
            cjsj = dic["采集时间"]
            dic.pop("采集时间")
            below,above={},{}
            dic, below, above = self.abnormalHandle[tableName].add(dic)
            dic["采集时间"] = cjsj
            self.setTreeItemStatus(tableName, True)
            dic['采集时间'] = dic['采集时间'].strftime('%H:%M')
            warn=""
            error=""
            cols = list(self.abnormalHandle[tableName].df.columns)
            field2Idx = {item: idx for idx, item in enumerate(cols)}
            label = classify(self.abnormalHandle[tableName].df.values.astype("float32"),
                             field2Idx,
                             self.abnormalHandle[tableName].thresh)
            if not label is None:
                type,desc=getDescribeByLabel(label)
                if type==0:
                    warn=desc
                else:
                    error=desc
            if warn!="":
                self.pte_log.appendHtml(normLog(cjsj.strftime('%H:%M')+" > ")+warnLog(getDeviceNameByTableName(self.deviceList,tableName)+warn))
            if error!="":
                self.pte_log.appendHtml(normLog(cjsj.strftime('%H:%M')+" > ")+errorLog(getDeviceNameByTableName(self.deviceList, tableName) + error))
            dic={'data':dic,'below':below,'above':above, 'warn':warn, 'error':error}
            text = json.dumps(dic)
            text=text.replace("NaN","null")
            return text

    def setTreeItemStatus(self,tableName,isRun):
        item=self.treeItemDict[tableName]
        if isRun:
            if item.isDisabled():
                item.setIcon(0,QIcon(IconDir+"greendot.svg"))
                item.setDisabled(False)
        else:
            if not item.isDisabled():
                item.setIcon(0,QIcon(IconDir + "reddot.svg"))
                item.setDisabled(True)

    def dbTimeout(self):
        if not self.doOnce:
            for tableName in self.widgetDisplay:
                config = eval(db.getConfigThresh(self.con, tableName))
                self.widgetDisplay[tableName].middle.thresh = json.dumps(config["thresh"])
                self.abnormalHandle[tableName]=AbnormalHandle(config["thresh"])
            self.doOnce=True
        for tableName in self.widgetDisplay:
            self.widgetDisplay[tableName].sendData()
        self.curTime=self.curTime.addSecs(60)

    def updateLogShowBtnLoc(self):
        windowSize=self.size()
        tbSize=self.tb_logShow.size()
        x=windowSize.width()-tbSize.width()-4
        y=windowSize.height()-tbSize.height()-15
        self.tb_logShow.move(x, y)

    def updateTreeShowBtnLoc(self):
        bannerSize=self.frame_banner.size()
        x=0
        y=94-self.tb_treeShow.height()#bannerSize.height()
        self.tb_treeShow.move(x, y)

    def onTreeItemClicked(self,item,column):
        if not item.isSelected():
            return
        zsbName=item.text(0)
        if zsbName==self.curWD.property("deviceName"):
            return
        for tableName in self.widgetDisplay:
            if self.widgetDisplay[tableName].property('deviceName')==zsbName:
                self.widgetDisplay[tableName].show()
                self.widgetDisplay[tableName].resizeLater(500)
                self.curWD=self.widgetDisplay[tableName]
            else:
                self.widgetDisplay[tableName].hide()


    def setComponentProperty(self):
        self.tb_min.setProperty("class","frameBtn")
        self.tb_max.setProperty("class", "frameBtn")
        self.tb_close.setProperty("class", "frameBtn")
        self.tb_display.setProperty("class","tabBtn")
        self.tb_train.setProperty("class", "tabBtn")
        self.tb_configThresh.setProperty("class", "tabBtn")
        self.tb_configRule.setProperty("class", "tabBtn")
        self.resetTabSelectStatus()

    def resetTabSelectStatus(self):
        self.tb_display.setProperty("selected", 'false')
        self.tb_train.setProperty("selected", 'false')
        self.tb_configThresh.setProperty("selected", 'false')
        self.tb_configRule.setProperty("selected", 'false')

    def setInfoNormal(self):
        self.labelInfo.setText('''<a style="color:green">运行正常</a>''')

    def connectSignals(self):
        self.timeTimer=QTimer()
        self.timeTimer.timeout.connect(self.updateTime)
        self.timeTimer.start(1000)
        self.widgetConfigThresh.tipSignal.connect(self.tipReceived)
        self.tb_min.clicked.connect(self.showMinimized)
        self.tb_max.clicked.connect(self.onMaximizeClicked)
        self.tb_close.clicked.connect(self.close)
        self.tb_display.clicked.connect(self.onTabClicked)
        self.tb_train.clicked.connect(self.onTabClicked)
        self.tb_configThresh.clicked.connect(self.onTabClicked)
        self.tb_configRule.clicked.connect(self.onTabClicked)
        self.tb_logHide.clicked.connect(self.onLogHideClicked)
        self.tb_logShow.clicked.connect(self.onLogShowClicked)
        self.tb_treeHide.clicked.connect(self.onTreeHideClicked)
        self.tb_treeShow.clicked.connect(self.onTreeShowClicked)
        for tableName in self.widgetDisplay:
            self.widgetDisplay[tableName].showMaximum.connect(self.onDisplayShowMaximum)
        self.pb_loadModel.clicked.connect(self.onLoadModelClicked)

        self.widgetTrainNet.logTransmit.connect(self.appendLog)


    def appendLog(self,s):
        self.pte_log.appendHtml(s)

    def onLoadModelClicked(self):
        path = QFileDialog.getExistingDirectory(self, "选择神经网络模型(.tf文件夹)")
        if path != "":
            self.le_loadModel.setText(path)

    def onDisplayShowMaximum(self,isMaximum):
        print('clicked')
        if isMaximum:
            self.sender().setParent(None)
            self.sender().showMaximized()
        else:
            self.sender().setParent(self)
            self.widgetDisplayContainer.layout().addWidget(self.sender())
            self.sender().showNormal()

    def onTabClicked(self):
        self.resetTabSelectStatus()
        sender=self.sender()
        if sender.property("selected")=="true":
            return

        self.curWD.hide()
        self.widgetDisplayContainer.hide()
        self.widgetTrainNet.hide()
        self.widgetConfigThresh.hide()
        self.widgetConfigRule.hide()
        sender.setProperty("selected", 'true');
        self.setStyle(QApplication.style())
        if sender==self.tb_display:
            self.widgetDisplayContainer.show()
            self.curWD.show()
            self.curWD.resizeLater(500)
        elif sender==self.tb_train:
            self.widgetTrainNet.show()
            self.widgetTrainNet.resizeLater(500)
        elif sender==self.tb_configThresh:
            self.widgetConfigThresh.show()
        elif sender==self.tb_configRule:
            self.widgetConfigRule.show()

    def onLogHideClicked(self):
        self.frame_log.hide()
        self.tb_logShow.show()

    def onLogShowClicked(self):
        self.tb_logShow.hide()
        self.frame_log.show()

    def onTreeHideClicked(self):
        self.frame_tree.hide()
        self.tb_treeShow.show()

    def onTreeShowClicked(self):
        self.tb_treeShow.hide()
        self.frame_tree.show()

    def updateTime(self):
        time = QDateTime().currentDateTime()
        s = time.toString("yyyy-MM-dd hh:mm:ss dddd")
        self.labelTime.setText(s)

    def tipReceived(self,tip):
        label=QLabel(tip)
        self.statusBar.addWidget(label)
        QTimer.singleShot(3000,lambda :self.statusBar.removeWidget(label))

    def mousePressEvent(self, event: QtGui.QMouseEvent):
        pos=event.pos()
        if self.frame_banner.geometry().contains(pos) and event.button()==Qt.LeftButton:
            self.dragging=True
            self.posBefore=pos
            self.setMouseTracking(True)

    def mouseReleaseEvent(self, event: QtGui.QMouseEvent):
        if self.dragging:
            self.dragging=False
            diff=event.pos()-self.posBefore
            self.move(self.x()+diff.x(),self.y()+diff.y())

    def onMaximizeClicked(self):
        if self.isMaximized():
            self.showNormal()
            self.tb_max.setIcon(QIcon(IconDir+"max.svg"))
        else:
            self.showMaximized()
            self.tb_max.setIcon(QIcon(IconDir+"restore.svg"))

    def resizeEvent(self, event: QtGui.QResizeEvent):
        self.updateLogShowBtnLoc()
        self.updateTreeShowBtnLoc()

    # def mouseMoveEvent(self, event: QtGui.QMouseEvent):
    #     if self.dragging:
    #         diff = event.pos() - self.posBefore
    #         x=self.x()
    #         y=self.y()
    #         self.posBefore=event.pos()
    #         self.move(x + diff.x(), y + diff.y())

if __name__=="__main__":
    import sys
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    exe = MainWidget()
    exe.showMaximized()
    for tableName in exe.widgetDisplay:
        exe.widgetDisplay[tableName].browser.page().setWebChannel(exe.widgetDisplay[tableName].channel)
    exe.widgetTrainNet.browser.page().setWebChannel(exe.widgetTrainNet.channel)
    sys.exit(app.exec_())